#include "plugin.h"
#include "kmy_adaptor.h"
#include <memory>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <pthread.h>

using namespace SwanLink::Finance;

KMY3501G_GM_Adaptor::KMY3501G_GM_Adaptor() {
    m_iFd = -1;
    m_timeout = 3000;
}

int KMY3501G_GM_Adaptor::Open(const Transport &tran) {
    m_iFd =  OpenComm(tran.dev, 9600, 0, 1, 8);
    if (m_iFd != 0) {
        m_iStatus = ERROR_KEYBOARD_OPEN_FAIL;
        return m_iStatus;
    }
    m_iStatus = SUCCESS;
    return m_iStatus;
}


KMY3501G_GM_Adaptor::~KMY3501G_GM_Adaptor() {
}

bool KMY3501G_GM_Adaptor::IsOpen() {
    if (m_iFd != 0) {
       return false;
    }
    char ver[256] = {0};
    int ret = GetVer(ver);
    if (ret == 0) {
       return true;
    }
    CloseComm();
    m_iFd = -1;
    return false;
}

int KMY3501G_GM_Adaptor::Close() {
    if (m_iFd == 0) {
       int result = CloseComm();
       if (result == 0) {
          m_iFd = -1;
          m_iStatus = SUCCESS;
          return SUCCESS;
       }
    }

    m_iStatus = ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    return m_iStatus;
}

int KMY3501G_GM_Adaptor::Reset() {
    if (m_iStatus != 0) {
        m_iStatus = ERROR_KEYBOARD_DEVICE_NOT_OPEN;
        return m_iStatus;
    }
    int ret = ResetSelfCheck();
    if (ret == 0) {
        m_iStatus = SUCCESS;
        std::cout << "Keboard Device Reset Success..." << std::endl;
        return SUCCESS;   // 设备复位成功
    }
    m_iStatus = ERR_KEYBOARD_HW_ERROR;
    return m_iStatus;
}

int KMY3501G_GM_Adaptor::GetStatus(int module, char *err) {
    char ver[256] = {0};
    int ret = GetVer(ver);
    if (ret != 0) {
        m_iStatus = ERR_DEVICE_NOT_OPEN;
    }
    return m_iStatus;
}

bool KMY3501G_GM_Adaptor::IsSM4Enabled() {
    return false;
}

int KMY3501G_GM_Adaptor::GetSN(char sn[], int &len) {
    if (m_iFd == 0) {
        int ret = GetDeviceNo(sn);
        if (ret == 1)
            return ERR_GET_SN;
        len = strlen(sn);
        return SUCCESS;
    }
    return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
}

int KMY3501G_GM_Adaptor::CalculateMAC(const KeyInfo& key, char plain[],
                                       int len, char enc_data[], int &enc_len) {
    if (m_iFd != 0)
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    enc_len = 0;
    if (m_iFd == 0) {
        if (key.keyID > 15 || key.keyID  < 0)
            return ERR_KEY_ID_OUT_OF_RANGE;
        if (key.keyType != 280 && key.keyType != 281 && key.keyType != 285)
            return ERR_KEY_TYPE_OUT_OF_RANGE;
        if (key.user_key_type != 261)
            return ERR_KEY_USER_TYPE_OUT_OF_RANGE;
        if (len <= 0)
            return ERR_PLAIN_DATA_NULL;
        int result =  CalcMacData(plain, enc_data);
        if (result == 1)
            return ERR_GET_MAC;
        enc_len = 8;
        return SUCCESS;
    }
    return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
}

int KMY3501G_GM_Adaptor::EncryptData(const KeyInfo& key, char plain[],
                                     int len, char enc_data[], int &len_enc) {
    if (m_iFd != 0)
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    len_enc = 0;
    if (m_iFd == 0) {
        if (key.keyID > 15 || key.keyID  < 0)
            return ERR_KEY_ID_OUT_OF_RANGE;
        if (key.keyType != 280 && key.keyType != 281 && key.keyType != 285)
            return ERR_KEY_TYPE_OUT_OF_RANGE;
        if (key.user_key_type != 262)
            return ERR_KEY_USER_TYPE_OUT_OF_RANGE;
        if (len <= 0)
            return ERR_PLAIN_DATA_NULL;
        int ret = Encrypt(plain, enc_data);
        if (ret == 1) {
            return ERR_ENCRYPT_DATA_FAIL;
        }
        len_enc = 8;
        return SUCCESS;
    }
    return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
}

int KMY3501G_GM_Adaptor::SetPINLength(int minLen, int maxLen) {
    if (!IsOpen())
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    if (minLen <= 0 || maxLen <= 0 || minLen > 6 || maxLen != 6)
        return ERR_DATA_OUT_OF_RANGE;
    if (maxLen <= minLen)
        return ERR_DATA_OUT_OF_RANGE;
    int ret = SetPinLen(maxLen);
    if (ret == 1)
      return ERR_SET_PINLEN_DATA;
    return ret;
}

int KMY3501G_GM_Adaptor::SetTextMode(TextMode mode) {
    if (!IsOpen())
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    if (mode == 1) {
        m_mode = mode;
        return SUCCESS;
    }
    m_mode = 0;
    return ERROR_KEYBOARD_DEVICE_NOT_SUPPORTED;
}

void KMY3501G_GM_Adaptor::ClearTextMode() {
    OnCharProcess(KEY_CLEAR, 0);
    return;
}

int KMY3501G_GM_Adaptor::LoadMasterKey(KeyID masterKeyID,
                                       unsigned char *KeyValue) {
    if (!IsOpen())
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    // char* reslut = (char*)KeyValue;
    if (KeyValue == nullptr)
        return ERR_KEY_VAULE_NULL;
    if (masterKeyID > 15 || masterKeyID < 0) {
        return ERR_KEY_ID_OUT_OF_RANGE;
    }
    int ret = ::LoadMasterKey((int)masterKeyID, (char*)KeyValue);
    if (ret == 1) {
        return ERROR;
    }
    int result = SetEncryptMode(0);
    return SUCCESS;
}

int KMY3501G_GM_Adaptor::LoadUserKey(KeyID masterKeyID,
                     userKeyType user_Key_Type, unsigned char *KeyValue) {
    if (!IsOpen())
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    if (masterKeyID > 15 || masterKeyID  < 0)
        return ERR_KEY_ID_OUT_OF_RANGE;
    if (user_Key_Type < 260 || user_Key_Type > 262)
       return ERR_KEY_USER_TYPE_OUT_OF_RANGE;
    if ((const char*)KeyValue == "")
        return ERR_KEY_VAULE_NULL;
    int ret = LoadWorkKey(masterKeyID, masterKeyID, reinterpret_cast<char*>(KeyValue));
    if (ret == 1) {
        return ERROR;
    }
    int result = SetEncryptMode(1);
    return SUCCESS;
}

int KMY3501G_GM_Adaptor::UpdateMasterKey(KeyID masterKeyID,
                                         unsigned char *KeyValue) {
    if (!IsOpen())
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    if (KeyValue == nullptr)
        return ERR_KEY_VAULE_NULL;
    if (masterKeyID > 15 || masterKeyID < 0) {
        return ERR_KEY_ID_OUT_OF_RANGE;
    }
    int ret = ::LoadMasterKey((int)masterKeyID, reinterpret_cast<char*>(KeyValue));
    if (ret == 1) {
        return ERROR;
    }
    int result = SetEncryptMode(1);
    return SUCCESS;
}

int KMY3501G_GM_Adaptor::UpdateUserKey(KeyID masterKeyID,
                    userKeyType user_Key_Type, unsigned char *KeyValue) {
    if (!IsOpen())
        return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    if (masterKeyID > 15 || masterKeyID  < 0)
        return ERR_KEY_ID_OUT_OF_RANGE;
    if (user_Key_Type != 260 && user_Key_Type != 261 && user_Key_Type != 262)
       return ERR_KEY_USER_TYPE_OUT_OF_RANGE;
    if (KeyValue == NULL)
        return ERR_KEY_VAULE_NULL;
    int ret = LoadWorkKey(static_cast<int>(masterKeyID), static_cast<int>(masterKeyID),
              reinterpret_cast<char*>(KeyValue));
    if (ret == 1) {
        return ERROR;
    }
    int result = SetEncryptMode(1);
    return SUCCESS;
}

int KMY3501G_GM_Adaptor::DeleteUserKey(KeyID masterKeyID,
                                       userKeyType user_Key_Type) {
    if (!IsOpen()) {
       return ERROR_KEYBOARD_DEVICE_NOT_OPEN;
    }
    if (masterKeyID > 15 || masterKeyID < 0 ) {
       return ERR_KEY_ID_OUT_OF_RANGE;
    }
    if (user_Key_Type < 260 && user_Key_Type > 262) {
      return ERR_KEY_USER_TYPE_OUT_OF_RANGE;
    }
    return ERROR_KEYBOARD_DEVICE_NOT_SUPPORTED;
}

void KMY3501G_GM_Adaptor::OnCharProcess(int code, char ch)
{
    switch (code) {
    case KEY_CHAR:
    case KEY_SHARP:
       if (keybuf_len < 6) {
            keybuf[keybuf_len++] = ch;
            OnResult(keybuf, keybuf_len);
             break;
       } else {
         OnFailed(ERR_KEYBOARD_OUT_OF_RANGE, "密码长度超出范围");
         break;
       }
    case KEY_OK:
        if (keybuf_len < 6) {
            OnFailed(ERR_KEYBOARD_LENGTH_TOO_SHORT, "密码长度过短");
        } else if (keybuf_len == 6) {
            OnResult(keybuf, keybuf_len);
            OnFailed(SUCCESS, "");
            break;
        } else if (keybuf_len > 6) {
            OnFailed(ERR_KEYBOARD_LENGTH_MECISM, "密码长度过长");
            break;
        }
    case KEY_BACKSPACE:
        if (keybuf_len <= 0) {
            OnFailed(ERR_KEYBOARD_HW_ERROR, "长度为0,无法退格");
            break;
        }
        keybuf[--keybuf_len] = '\0';
        OnResult(keybuf, keybuf_len);
        break;
    case KEY_RETURN:
    case KEY_CLEAR:
        keybuf_len = 0;
        keybuf[0] = '\0';
        OnResult(keybuf, keybuf_len);
        break;
    case KEY_UP:
    case KEY_DOWN:
    case KEY_DROP:
         OnFailed(ERR_KEYBOARD_INVALID_KEY, "无效字符");
         break;
    case KEY_EXIT:
        break;
    }
}

void KMY3501G_GM_Adaptor::OnFailed(int code, const std::string &err)
{
    if (pinListener) {
        pinListener->OnFailed(code, err);
    }
}

void KMY3501G_GM_Adaptor::OnResult(char *buf, int len)
{
    if (pinListener) {
        pinListener->OnResult(buf, len);
    }
}

void KMY3501G_GM_Adaptor::ListenForRead()
{
    flag = true;
    keybuf_len = 0;

    int ret = EnableGetdata();
    if (ret != 0) {
        OnFailed(ERR_DEVICE_ACTIVE_FAIL, "激活获取数据失败");
        return;
    }
    clock_t start1, finish1, internalTime1;
    if (m_timeout > 30000) {
        OnFailed(ERR_KEYBOARD_TIME_OUT_OF_RANGE, "键盘监听值超出范围");
        KeyboardClose();
        return;
    }
    internalTime1 = m_timeout*1000;
    start1 = clock();
    while (flag) {
        finish1 = clock();
        if ((finish1 - start1) > internalTime1) {
            OnFailed(ERR_KEYBOARD_INPUT_TIME_OUT, "键盘输入超时");
            break;
        }
        char ch = 0;
        int ret  = CheckPressedBuf(&ch, m_timeout);
        if (ret == 1) {
            continue;
        }
        if (ch >= '0' && ch <= '9') {
            if (m_mode == 1) {
                ch = '*';
              OnCharProcess(KEY_CHAR, ch);
            } else {
               OnCharProcess(KEY_CHAR, ch);
            }
        } else if (ch == 0x2e) {
            OnCharProcess(KEY_DROP, ch);
        } else if (ch == 0x1b) {
            OnCharProcess(KEY_RETURN, ch);
            flag = false;
        } else if (ch == 0x0d) {
            OnCharProcess(KEY_OK, ch);
            flag = false;
        } else if (ch == 0x08) {
            OnCharProcess(KEY_BACKSPACE, ch);
        } else if (ch == 0x21) {
            OnCharProcess(KEY_UP, ch);
            flag = false;
        } else if (ch == 0x22) {
            OnCharProcess(KEY_DOWN, ch);
            flag = false;
        } else {
            OnFailed(ERR_KEYBOARD_READKEY_UNKNOWN, "读取到未知键值");
        }
        start1 = clock();
    }
    KeyboardClose();
    flag = false;
}

void KMY3501G_GM_Adaptor::ListenForPin(PinListener* listener, int timeout) {
    do {
        std::lock_guard<std::mutex> lock(pin_mutex);
        flag = false;
        m_timeout = timeout;
        pinListener = listener;
    }while(false);
    pthread_create(&pin_thread_id, NULL, ListenForPinThread, this);
    pthread_join(pin_thread_id, NULL);
    pinListener = nullptr;
}


// 插件接口实现
std::shared_ptr<IAdaptor> CreateAdaptor() {
    return std::make_shared<KMY3501G_GM_Adaptor>();
}
Transport GetAccess(ACCESS_MODE mode, const char *dev)
{
    if (mode == AM_SERIAL) {
       SerialTransport tran;
       tran.mode = mode;
       tran.size = sizeof(SerialTransport);
       strcpy(tran.dev, dev);
       tran.timeout = 5000;
       tran.baudrate = 9600;
       tran.databit = 8;
       tran.stopbit = 1;
       tran.parity = 0;
       return tran;
    } else {
        UsbTransport tran;
        tran.mode = mode;
        tran.size = sizeof(UsbTransport);
        strcpy(tran.dev, dev);
        tran.timeout = 5000;
        return tran;
    }
}

static Plugin g_plugin = {
    .CreateAdaptor = CreateAdaptor,
    .GetAccess = GetAccess,
    .version = "1.0",
    .name = "KMY3501G_GM",
    .desc = "KMY3501G_GM KeyBoard Adaptor 1.0",
    .id = 0x0301
};

PLUGIN_INIT(&g_plugin)